package com.tanhua.server.service;


import com.alibaba.fastjson.JSON;
import com.tanhua.commons.exception.TanHuaException;
import com.tanhua.commons.templates.FaceTemplate;
import com.tanhua.commons.templates.HuanXinTemplate;
import com.tanhua.commons.templates.OssTemplate;
import com.tanhua.commons.templates.SmsTemplate;
import com.tanhua.manage.domain.db.User;
import com.tanhua.manage.domain.db.UserInfo;
import com.tanhua.manage.domain.mongo.RecommendUser;
import com.tanhua.manage.domain.vo.*;
import com.tanhua.dubbo.api.*;
import com.tanhua.server.interceptor.UserHolder;
import com.tanhua.server.utils.GetAgeUtil;
import com.tanhua.server.utils.JwtUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.dubbo.common.utils.CollectionUtils;
import org.apache.dubbo.config.annotation.Reference;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Service
@Slf4j
public class UserService {
    @Autowired
    private JwtUtils jwtUtils;
    @Reference
    private UserApi userApi;
    @Autowired
    private SmsTemplate smsTemplate;
    @Autowired
    private FaceTemplate faceTemplate;
    @Autowired
    private OssTemplate ossTemplate;
    @Reference
    private UserInfoApi userInfoApi;
    @Reference
    private FriendApi friendApi;
    @Reference
    private UserLikeApi userLikeApi;
    @Reference
    private VisitorApi visitorApi;

    /**
     * 手机验证码key的前缀
     */
    @Value("${tanhua.redisValidateCodeKeyPrefix}")
    private String redisValidateCodeKeyPrefix;

    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private HuanXinTemplate huanXinTemplate;

    /**
     * 根据手机号查询用户
     * @return
     */
    public User findByMobile(String phone){
        User user = userApi.findByMobile(phone);
        return user;
    }

    /**
     * 新增用户
     * @param
     * @return
     */
    public void saveUser(User user){
        userApi.save(user);
    }
    /**
     * 注册登陆 - 发送验证码
     * @param phone
     * @return
     */
    public void sendValidateCode(String phone) {
        //通过手机号码获取redis中的验证码
        String key =redisValidateCodeKeyPrefix + phone;
        String codeInRedis = (String) redisTemplate.opsForValue().get(key);
        log.info("codeInRedis:{},{}",codeInRedis,phone);
        //如果redis中的验证码有值，就报错：验证码还未失效
        if (null != codeInRedis){
            throw new TanHuaException(ErrorResult.duplicate());
        }
        //没有值
        //生成验证码
        String validateCode = "123456";//RandomStringUtils.randomNumeric(6);
        log.info("发送验证码成功。{},{}",validateCode,phone);
        /*//调用smstemplate发送验证码
        Map<String, String> sendResult = smsTemplate.sendValidateCode(phone, validateCode);
        //如果发送返回的结果不为空，说明发送失败 了
        if (sendResult != null){
            throw new TanHuaException(ErrorResult.fail());
        }*/
        //将验证码存入redis ，设置有效期10分钟
        redisTemplate.opsForValue().set(key,validateCode,10, TimeUnit.MINUTES);
    }

    /**
     * 注册登录-第一步：验证码校验(登录)
     */
    public Map<String, Object> loginVerification(String phone, String verificationCode) {

        //1.校验验证码
        //1.1.拼接验证码的key
        String key =redisValidateCodeKeyPrefix + phone;
        //1.2.从redis中去取验证码
        String codeInRedis = (String) redisTemplate.opsForValue().get(key);
        log.info("codeInRedis,verificationCode:{},{}",codeInRedis,verificationCode);
        //1.2.1验证码过期。。。报错
        if (null ==codeInRedis){
            throw new TanHuaException(ErrorResult.loginError());
        }
        //1.2.2没过期，将两个验证码对比
        if (!StringUtils.equals(codeInRedis,verificationCode)){
            //1.2.2.1不一致，报错
            throw new TanHuaException(ErrorResult.validateCodeError());
        }
        //1.2.2.2一致，删除redis中验证码的key，防止重复提交
        redisTemplate.delete(key);
        //2.获取手机号，判断用户是否已注册过
        //2.1 从数据库查询手机号对比
        User user = userApi.findByMobile(phone);
        //2.1.2如果不存在，就注册为新用户
        boolean isNew = false;//默认是已注册
        if (null == user){
            user = new User();
            user.setMobile(phone);
            //密码使用手机后6位
            user.setPassword(DigestUtils.md2Hex(phone.substring(5)));
            Long userId = userApi.save(user);
            user.setId(userId);
            isNew = true;
            // 注册环信上的账号
            huanXinTemplate.register(userId);
        }
        //2.1.1如果注册过了，直接登录

        //3.签发token，要用到id和手机号
        String token = jwtUtils.createJWT(phone, user.getId());
        //3.1以token为key，以用户信息为value，存入redis，有效期设置7天
        String userJsonString = JSON.toJSONString(user);
        String tokenKey = "TOKEN_" + token;
        redisTemplate.opsForValue().set(tokenKey,userJsonString,7,TimeUnit.DAYS);
        //4.构建返回数据{token，isNew}
        Map<String,Object> result = new HashMap<>();
        result.put("token",token);
        result.put("isNew",isNew);
        return result;

    }

    /**
     * 通过token获取登陆用户信息
     * @param token
     * @return
     */
   /* public User getUserByToken(String token){
        //将token拼接前缀，组成redis的key
        String tokenKey = "TOKEN_" + token;
        System.out.println("tokenKey:"+tokenKey);
        //使用这个key从redis里拿出user的json数据
        String userJsonString = ((String) redisTemplate.opsForValue().get(tokenKey));
        System.out.println("userJsonString:"+userJsonString);
        //如果没有数据，就返回登录失败
        if (null == userJsonString){
            throw new TanHuaException("登陆超时，请重新登录");
        }
        //续期
        redisTemplate.expire(tokenKey,1,TimeUnit.DAYS);
        //获取登录用户的id
        User user = JSON.parseObject(userJsonString, User.class);
        return user;
    }*/
    /**
     * 完善用户信息
     * @param userInfoVo
     */
    public void loginReginfo(UserInfoVo userInfoVo) {
        // 验证token是否有效
        //User loginUser = getUserByToken(token);
        long loginUserId = UserHolder.getUserId();

        // vo转成db的pojo
        UserInfo userInfo = new UserInfo();
        // 复制属性值，把p1复制到p2里去，属性名及类型必须一致。如果不一致则不会复制
        BeanUtils.copyProperties(userInfoVo,userInfo);
        userInfo.setAge(GetAgeUtil.getAge(userInfoVo.getBirthday()));
        // 防止数据混乱，数据库中的id手动控制
        userInfo.setId(loginUserId);
        //调用api添加用户信息
        userInfoApi.add(userInfo);
    }

    /**
     * 完善用户信息  选取头像
     * @param headPhoto

     */
    public void uploadAvatar(MultipartFile headPhoto) {
        //通过token获取用户
        Long userId = UserHolder.getUserId();

        //人脸检测
        try {
            if (!faceTemplate.detect(headPhoto.getBytes())){
                log.info("人脸识别错误");
                throw new TanHuaException(ErrorResult.faceError());
            }
            //上传到oss
            String url = ossTemplate.upload(headPhoto.getOriginalFilename(),headPhoto.getInputStream());
            //调用api更新头像
            UserInfo userInfo = new UserInfo();
            userInfo.setId(userId);
            userInfo.setAvatar(url);

            userInfoApi.update(userInfo);
        } catch (IOException e) {
            log.error("上传头像失败",e);
            throw new TanHuaException("上传头像失败");
        }
    }

    /**
     * 获取登陆用户信息
     * @param
     * @return
     */
    public UserInfoVo getUserInfo() {

        //User user = getUserByToken(token);
        long userID = UserHolder.getUserId();
        UserInfo userInfo = userInfoApi.findById(userID);
        UserInfoVo userInfoVo = new UserInfoVo();

        Integer age = userInfo.getAge();
        System.out.println("age = " + age);
        String ageStr = age.toString();
        System.out.println("ageStr = " + ageStr);

        BeanUtils.copyProperties(userInfo,userInfoVo);
        userInfoVo.setAge(ageStr);

        log.info("userInfoVo: "+userInfoVo);
        return userInfoVo;
    }

    /**
     * 更新用户信息
     * @param userInfoVo
     */
    public void updateUserInfo(UserInfoVo userInfoVo) {

        long userId = UserHolder.getUserId();

        UserInfo userInfo = userInfoApi.findById(userId);
        BeanUtils.copyProperties(userInfoVo,userInfo);

        userInfoApi.update(userInfo);
    }
    /**
     * 更新用户头像
     */
    public void updateAvatar(MultipartFile headPhoto){
        //获取登录用户的id
        long id = UserHolder.getUserId();




        try {
            if (!faceTemplate.detect(headPhoto.getBytes())){
                log.info("人脸识别失败，更新取消");
                throw new TanHuaException(ErrorResult.faceError());
            }
            //识别成功 上传到阿里云
            String url = ossTemplate.upload(headPhoto.getOriginalFilename(),headPhoto.getInputStream());

            //获取头像地址
            UserInfo userInfo = userInfoApi.findById(id);
            String avatarUrl = userInfo.getAvatar();
            //调用api更新头像
            userInfo.setAvatar(url);

            userInfoApi.update(userInfo);
            //删除旧头像
            ossTemplate.deleteFile(avatarUrl);
        } catch (IOException e) {
            log.error("头像更新失败",e);

        }
    }

    /**
     * 互相喜欢、喜欢、粉丝统计
     * @return
     */
    public CountsVo counts() {
        Long userId = UserHolder.getUserId();
        Long eachLoveCount = friendApi.countByUserId(userId);

        Long loveCount = userLikeApi.loveCount(userId);
        Long fanCount = userLikeApi.fanCount(userId);
        return  new CountsVo(eachLoveCount,loveCount,fanCount);


    }

    /**
     * 互相喜欢、喜欢、粉丝、谁看过我 - 翻页列表
     * @param type
     * 1 互相关注
     * 2 我关注
     * 3 粉丝
     * 4 谁看过我
     * @return
     */
    public PageResult<FriendVo> queryUserLikeList(int type, Long page, Long pageSize) {
        //根据type调整api查询，返回统计的数据类型
        PageResult pageResult = null;
        boolean alreadyLove = false;
        switch (type){
            case 1:
                pageResult = friendApi.findPageWithScore(UserHolder.getUserId(),page,pageSize);
                alreadyLove = true;
                break;
            case 2:
                pageResult = userLikeApi.findPageOneSideLike(UserHolder.getUserId(),page,pageSize);
                alreadyLove = true;
                break;
            case 3:
                pageResult = userLikeApi.findPageFens(UserHolder.getUserId(),page,pageSize);
                break;
            case 4:
                pageResult = visitorApi.findPageByUserId(UserHolder.getUserId(), page, pageSize);
                break;
            default:
                throw new TanHuaException("参数不正确");
        }
        List<RecommendUser> items = pageResult.getItems();
        if (!CollectionUtils.isEmpty(items)){

            List<Long> recommendUserIds = items.stream().map(RecommendUser::getUserId).collect(Collectors.toList());
            Map<Long, UserInfo> userInfoMap = userInfoApi.findByBatchId(recommendUserIds).stream().collect(Collectors.toMap(UserInfo::getId, u -> u));
            //5. 转成成vo
            Boolean finalAlreadyLove = alreadyLove;
            List<Object> voList = items.stream().map(recommendUser -> {
                FriendVo vo = new FriendVo();
                // 取出用户的信息
                UserInfo userInfo = userInfoMap.get(recommendUser.getUserId());
                // 属性复制
                BeanUtils.copyProperties(userInfo, vo);
                // 缘分值
                vo.setMatchRate(recommendUser.getScore().intValue());
                vo.setAlreadyLove(finalAlreadyLove);
                return vo;
            }).collect(Collectors.toList());
            pageResult.setItems(voList);
        }
        return pageResult;
    }

    /**
     * 粉丝 - 喜欢
     * @param fansId
     */
    public void fansLike(Long fansId) {
        Long userId = UserHolder.getUserId();
        Boolean flag = userLikeApi.fansLike(userId,fansId);
        if (flag){
            huanXinTemplate.makeFriends(userId,fansId);
        }
    }
}
